package cndw.core.dispatch;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cndw.core.cfg.ServerConfig;
import cndw.core.dispatch.annotation.Action;
import cndw.core.dispatch.annotation.Action.CacheTarget;
import cndw.core.dispatch.annotation.Action.User;
import cndw.core.dispatch.exception.ActionFilterException;
import cndw.core.dispatch.exception.ActionInvokeException;
import cndw.core.dispatch.exception.ActionNotFoundException;
import cndw.core.util.LogConst;
import cndw.core.util.Sign;

/**
 * 默认转发器,用Spring注入
 * @author zuojie.x
 */
public class CoreDispatcher implements Dispatcher {
	private final Logger log = LoggerFactory.getLogger(LogConst.CORE);
	
	private ActionManager actionManager;
	private ActionFilterExecutor actionFilterExecutor;
	
	public CoreDispatcher(ActionManager actionManager) {
		this.actionManager = actionManager;
		actionFilterExecutor = actionManager.getActionFilterExecutor();
	}
	
	/** 业务执行服务 */
	private ExecutorService executorService = Executors
			.newFixedThreadPool(ServerConfig.BUSINESS_THREADS > 0 ? ServerConfig.BUSINESS_THREADS
					: Runtime.getRuntime().availableProcessors() * 2);

	/** 登陆验证 */
	private final boolean LoginCheckOpen = ServerConfig.booleanValue("LoginCheckOpen");
	private final long ActionInvokeTimeWarn = ServerConfig.longValue("ActionInvokeTimeWarn");
			
	@Override
	public void dispatch(final Request request) {
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				ActionExecutor actionExecutor = actionManager.getActionExecutor(request);
				// 控制器的注解
				Action action = actionExecutor.getActionAnnotation();
				if (User.Player == action.user()) {
					// 登陆验证
					if (LoginCheckOpen && action.loginCheck() && !request.getSession().isLogin()) {
						write(ResponseFactory.fail(ResponseCode.NOT_LOGIN));
						return;
					}
				} else if (User.System == action.user()) {
					// Sign验证
					if (!Sign.createSign(request).equals(request.getSign())) {
						write(ResponseFactory.create(ResponseCode.ACTION_SIGN_ERROR, request));
						return;
					}
				}
				long startTime = System.currentTimeMillis();
				if (log.isDebugEnabled())
					log.debug(request.toString());
				// 设置request到ThreadLocal
				ThreadLocalRequest.set(request);
				actionFilterExecutor.beforeAction(request);
				String playerId = request.getPlayerId();
				Response response = null; // 执行结果
				try {
					if (L1Cache.IsOpen && action.cache() != CacheTarget.NONE) {
						if (!request.getSession().isLogin()) {
							write(ResponseFactory.create(ResponseCode.NOT_LOGIN, request));
							return;
						}
						// 如果使用缓存,不需要执行actionMethod,直接返回结果
						response = L1Cache.get(playerId, actionExecutor, action.cache());
						if (response != null) {
							write(response);
							return;
						}
					}
					long invokeStart = System.currentTimeMillis();
					Object invokeResult = actionExecutor.execute();
					long invokeFinish = System.currentTimeMillis();
					if (invokeResult != null) {
						if (!(invokeResult instanceof Response)) {
							// 类型不是Response时按成功处理
							response = ResponseFactory.ok(request, invokeResult);
						} else {
							response = (Response) invokeResult;
						}
					}
					// action执行后过滤器
					actionFilterExecutor.afterAction(request, response);
					if (L1Cache.IsOpen && action.cache() != CacheTarget.NONE) {
						// 加入缓存
						L1Cache.put(playerId, actionExecutor, response, action.cache());
					}
					// 超时不返回
					if (action.timeout() > 0 && 
							invokeFinish - invokeStart > action.timeout())
						return;
					if (response != null)
						write(response);
				} catch (ActionFilterException afe) {
					afe.printStackTrace();
					if (log.isDebugEnabled())
						write(ResponseFactory.create(ResponseCode.ACTION_FILTER_ERROR, request));
				} catch (ActionNotFoundException anfe) {
					anfe.printStackTrace();
					if (log.isDebugEnabled())
						write(ResponseFactory.create(ResponseCode.ACTION_NOT_EXISTS, request));
				} catch (ActionInvokeException aie) {
					aie.printStackTrace();
					if (log.isDebugEnabled())
						write(ResponseFactory.create(ResponseCode.ACTION_ERROR, request));
				} catch (Exception e) {
					e.printStackTrace();
					if (log.isDebugEnabled())
						write(ResponseFactory.fail(request));
				} finally {
					// 删除线程变量request
					ThreadLocalRequest.remove();
					if (log.isDebugEnabled())
						log.debug(response.toString());
					long useTime = System.currentTimeMillis() - startTime;
					if (useTime > ActionInvokeTimeWarn) {
						log.warn("{}执行时间超过{}ms! useTime:{}", new Object[] { actionExecutor, ActionInvokeTimeWarn, useTime });
					}
				}
			}
		});
	}
	
	void write(Response response) {
		ThreadLocalRequest.get().getSession().getChannel().write(response);
	}
	
	@Override
	public void stop() {
		executorService.shutdown();
		try {
			for (int i = 0; i < 6; i ++) {
				if (executorService.awaitTermination(5000L, TimeUnit.MILLISECONDS))
					break;
			}
			if (!executorService.isTerminated())
				executorService.shutdownNow();
		} catch (InterruptedException e) {
			executorService.shutdownNow();
			e.printStackTrace();
		}
	}
}
